﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Onetube.Entities.ChannelMostViewedQuery;
using Onetube.Entities.ChannelsQuery;
using Onetube.Providers.Interfaces;

namespace Onetube.Providers
{
    public class YoutubeChannelProvider : IYoutubeChannelProvider
    {
        public Task<Entities.ChannelsQuery.ChannelsQueryResult> SearchChannelByIdAsync(string id, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/channels?");

            petitionUri.AppendFormat("part={0}", "snippet%2CbrandingSettings%2Cstatistics%2CtopicDetails%2CinvideoPromotion%2CcontentDetails");
            petitionUri.AppendFormat("&id={0}", id);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<ChannelsQueryResult>();
           
            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
        }

        public Task<ChannelsQueryResult> GetMyChannelInfoAsync(string Token, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/channels?");

            petitionUri.AppendFormat("part={0}", "snippet%2CcontentDetails%2Cstatistics%2CtopicDetails%2CinvideoPromotion");
            petitionUri.AppendFormat("&mine={0}", "true");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            petitionUri.AppendFormat("&access_token={0}", Token);
            var taskCompletitionSource = new TaskCompletionSource<ChannelsQueryResult>();
           
            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask, Token);
        }

        public async Task<Models.SearchChannel.SearchChannelResult> GetMostViewedChannelsAsync(string RegionCode, string maxResults, CancellationTokenSource cancelTask)
        {
            //https://gdata.youtube.com/feeds/api/channelstandardfeeds/MX/most_viewed?v=2&alt=json
            StringBuilder petitionUri = new StringBuilder("https://gdata.youtube.com/feeds/api/channelstandardfeeds/");

            petitionUri.AppendFormat("{0}", RegionCode);
            petitionUri.AppendFormat("/most_viewed?v={0}", 2);
            petitionUri.AppendFormat("&alt={0}", "json");
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<Entities.ChannelMostViewedQuery.ChannelMostViewedQueryResult>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            var channelResult = new Models.SearchChannel.SearchChannelResult();
            channelResult.Items = new List<Models.SearchChannel.Item>();
            if (result != null)
            {
                if (result.Feed != null)
                {
                    if (result.Feed.Entry.Any())
                    {
                        foreach (var entry in result.Feed.Entry)
                        {
                            try
                            {
                                var item = new Models.SearchChannel.Item();
                                var snippet = new Models.SearchChannel.Snippet();
                                var statistics = new Models.SearchChannel.Statistics();
                                item.Id = entry.YtChannelId.T;
                                if (entry.Summary != null)
                                    snippet.Description = entry.Summary.T;
                                if (entry.Updated != null)
                                    snippet.PublishedAt = entry.Updated.T;
                                snippet.Thumbnails = new Models.SearchChannel.Thumbnails()
                                {
                                    Default = new Models.SearchChannel.Default { Url = entry.MediaGroup.MediaThumbnail.FirstOrDefault().Url }
                                };
                                snippet.Title = entry.Title.T;
                               
                                statistics.CommentCount = entry.YtChannelStatistics.CommentCount;
                                statistics.SubscriberCount = entry.YtChannelStatistics.SubscriberCount;
                                statistics.VideoCount = entry.YtChannelStatistics.VideoCount;
                                statistics.ViewCount = entry.YtChannelStatistics.ViewCount;

                                item.Statistics = statistics;

                                item.Snippet = snippet;
                                channelResult.Items.Add(item);
                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
            }
            var filteredResults = channelResult.Items.Take(System.Convert.ToInt32(maxResults));
            channelResult.Items = filteredResults.ToList();
            filteredResults = null;
            result = null;
            return channelResult;
        }

        private async Task<Entities.ChannelMostViewedQuery.ChannelMostViewedQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<Entities.ChannelMostViewedQuery.ChannelMostViewedQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
            HttpWebRequest request = HttpWebRequest.CreateHttp(petitionUri.ToString());
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<ChannelMostViewedQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        private async Task<ChannelsQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<ChannelsQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
            HttpWebRequest request = HttpWebRequest.CreateHttp(petitionUri.ToString());
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync();

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<ChannelsQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        private async Task<ChannelsQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<ChannelsQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask, string token)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("Authorization", "Bearer  " + token);
           
            HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
            string resultJson;
            using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
            {
                try
                {
                    resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                    if (!string.IsNullOrEmpty(resultJson))
                    {
                        var entries = JsonConvert.DeserializeObject<ChannelsQueryResult>(resultJson);

                        taskCompletitionSource.SetResult(entries);
                        resultJson = null;
                        entries = null;
                    }
                    else
                    {
                        taskCompletitionSource.SetResult(null);
                    }
                    response.Dispose();

                }
                catch (Exception ex)
                {
                    taskCompletitionSource.SetException(ex);
                    client.Dispose();
                }
            }
            client.Dispose();
            response.Dispose();
            return await taskCompletitionSource.Task;
        }
    }
}